package org.bhf.providers.ccache;

/**
 * Copyright (c) 2007, Blue Hole Software. All rights reserved.
 * Code licensed under the Apache 2.0 License:
 * http://www.apache.org/licenses/
 */

import java.lang.ref.SoftReference;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Implementation of <code>ComponentStateCache</code> based on an LRU cache with weak references.
 */
public class LRUComponentStateCache implements ComponentStateCache
{
    private final   Map<String,SoftReference<?>>    components;
    private         int                             sizeLimit   = 1024;

    public LRUComponentStateCache()
    {
        components = new LinkedHashMap<String,SoftReference<?>>( 128, .75F, true )
        {
            final public static long serialVersionUID = 1L; // Just to suppress warnings

            public boolean removeEldestEntry( final Map.Entry eldest )
            {
                return size() > LRUComponentStateCache.this.sizeLimit;
            }
        };
    }

    /**
     * @inheritDoc
     */
    public synchronized Object  recallComponent( final String clazz, final long ID, final int version )
    {
        final String                key     = clazz + '.' + Long.toString( ID ) + '.' + Integer.toString( version );
        final SoftReference<?> wrapper = components.get( key );

        if( wrapper == null )
        {
            return null;
        }
        else if( wrapper.get() == null )
        {
            components.remove( key );
            return null;
        }
        else
        {
            return wrapper.get();
        }
    }

    /**
     * @inheritDoc
     */
    public synchronized void    rememberComponent( final String clazz, final long ID, final int version, final Object component )
    {
        final String  key  = clazz + '.' + Long.toString( ID ) + '.' + version;

        components.put( key, new SoftReference<Object>( component ) );
    }

    /**
     * @inheritDoc
     */
    public void                 setLimit( final int sizeLimit )
    {
        this.sizeLimit  = sizeLimit;
    }

    /**
     * @inheritDoc
     */
    public int                  getLimit()
    {
        return sizeLimit;
    }

    /**
     * @inheritDoc
     */
    public synchronized void    clear()
    {
        components.clear();
    }
}
